package com.ys.utils.mobao;

//import com.sm2.SM2Utils;
//import com.util.Util;

import com.ys.utils.base.j2se.Logger;
import com.ys.utils.spring.config.SystemError;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;

public class Mobo360SignUtil {

	private static PrivateKey privateKey = null;
	private static X509Certificate cert = null;
	private static String signType = Mobo360Config.SIGN_TYPE;
	private static final String CHAR_SET = "UTF-8";
	private static String key = "";
	private static String pri = "";

	private Mobo360SignUtil() {

	}

	public static void init() throws Exception {
		if ("RSA".equals(signType)) {
			initRAS(Mobo360Config.PFX_FILE, Mobo360Config.CERT_FILE,
					Mobo360Config.PASSWD);
		} else if ("MD5".equals(signType)) {
			initMD5();
		}
//		else if ("SM".equals(signType)){
//			initSM();
//		}
	}
	/**
	 * 国密证书SM签名初始化
	 *
	 */
//	public static void initSM() throws Exception {
//		if(StringUtils.isBlank(Mobo360Config.pri_url)){
//			System.out.println("国密私钥路径为空，请检查！");
//		}
//		//从dat文件获取私钥
//		File file = new File(Mobo360Config.pri_url);
//		FileInputStream in = new FileInputStream(file);
//		byte[] temp = new byte[in.available()];
//		in.read(temp);
//		String fileData = Util.byteToHex(temp);
//		in.close();
//		pri = Util.getPriKey(fileData);
//		System.out.println("国密私钥初始化完成，私钥："+pri);
//	}
	/**
	 * MD5签名初始化
	 * 
	 */
	public static void initMD5() throws Exception {
		key = Mobo360Config.MD5_KEY;
	}

	/**
	 * RAS签名初始化
	 * 
	 * @param pfxFilePath
	 *            签名私钥文件的绝对路径
	 * @param certFilePath
	 *            验证签名文件的绝对路径
	 * @param pfxPwd
	 *            私钥文件的密码
	 */
	public static void initRAS(String pfxFilePath, String certFilePath,
                               String pfxPwd) throws Exception {
		if (StringUtils.isBlank(pfxFilePath)) {
			Logger.error("私钥文件路径不能为空！");
		}
		if (StringUtils.isBlank(certFilePath)) {
			Logger.error("公钥文件路径不能为空！");
		}
		if (StringUtils.isBlank(pfxPwd)) {
			Logger.error("私钥密码不能为空！");
		}
		if (privateKey == null || cert == null) {
			InputStream is = null;
			try {
				KeyStore ks = KeyStore.getInstance("PKCS12");
				is = new FileInputStream(pfxFilePath);
				if (is == null) {
					Logger.error("证书文件路径不正确！");
				}
				String pwd = pfxPwd;
				ks.load(is, pwd.toCharArray());
				String alias = "";
				Enumeration<String> e = ks.aliases();
				while (e.hasMoreElements()) {
					alias = e.nextElement();
				}
				privateKey = (PrivateKey) ks.getKey(alias, pwd.toCharArray());
				CertificateFactory cf = CertificateFactory.getInstance("X.509");
				is = new FileInputStream(certFilePath);
				if (is == null) {
					Logger.error("证书文件路径不正确!！");
				}
				cert = (X509Certificate) cf.generateCertificate(is);
				is.close();
			} catch (Exception e) {
				Logger.error("签名初始化失败！",e);
			} finally {
				if (null != is) {
					is.close();
				}
			}
		}
	}

	/**
	 * 生成签名
	 * 
	 * @param sourceData  拼接好的字符串
	 * @return
	 * @throws Exception
	 */
	public static String signData(String sourceData) throws Exception {
		String signStrintg = "";
		if ("RSA".equals(signType)) {
			if (null == privateKey) {
				Logger.error("签名尚未初始化！");
				SystemError.wrapBs("500","签名尚未初始化！");
			}
			if (StringUtils.isBlank(sourceData)) {
				Logger.error("签名数据为空！");
				SystemError.wrapBs("500","签名数据为空！");
			}
			Signature sign = Signature.getInstance("MD5withRSA");
			sign.initSign(privateKey);
			sign.update(sourceData.getBytes("utf-8"));
			byte[] signBytes = sign.sign();
			return Base64.encodeBase64String(signBytes).replaceAll("\r", "").replaceAll("\n", "");
		} else if ("MD5".equals(signType)) {
			signStrintg = signByMD5(sourceData, key);
//            System.out.println("MD5签名值："+signStrintg);
		}
//		else if ("SM".equals(signType)){
//			//私钥签名
//			String signData = SM2Utils.Signature(Mobo360Config.userID, pri, sourceData);
//			System.out.println("国密签名值(16进制)："+signData.toUpperCase());
//			return signData;
//		}
		signStrintg.replaceAll("\r", "").replaceAll("\n", "");
		return signStrintg;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static String coverMap2String(Map data) throws Exception {
		List<String> list = new ArrayList<String>(data.keySet());
		Collections.sort(list);

		StringBuilder sf = new StringBuilder();
		for (String key : list) {
			Object value = data.get(key);

			if (StringUtils.isEmpty(key)||null==value|| StringUtils.isEmpty(value.toString())||"null".equals(value.toString())) {
				continue;
			}
			sf.append(key).append("=").append(value).append("&");
		}
		if(sf.length()>0){
			return sf.substring(0, sf.length() - 1);
		}

		return sf.toString();
	}

	/**
	 * 验证签名
	 * 
	 * @param signData
	 *            签名数据
	 * @param srcData
	 *            原数据   拼接好格式的原数据
	 * @return
	 * @throws Exception
	 */
	public static boolean verifyData(String signData, String srcData)
			throws Exception {
		if ("RSA".equals(signType)) {
			if (null == cert) {
				throw new Exception("签名尚未初始化！");
			}
			if (StringUtils.isBlank(signData)) {
				throw new Exception("系统校验时：签名数据为空！");
			}
			if (StringUtils.isBlank(srcData)) {
				throw new Exception("系统校验时：原数据为空！");
			}
			java.util.Base64.Decoder decoder = java.util.Base64.getMimeDecoder();
			byte[] b = decoder.decode(signData);
			Signature sign = Signature.getInstance("MD5withRSA");
			sign.initVerify(cert);
			sign.update(srcData.getBytes("utf-8"));
			return sign.verify(b);
		} else if ("MD5".equals(signType)) {
			if (signData.equalsIgnoreCase(signByMD5(srcData, key))) {
				return true;
			} else {
				return false;
			}
		}
//		else if("SM".equals(signType)){
//			Boolean flag = SM2Utils.verifySignSM2_ZA(Mobo360Config.userID, Mobo360Config.cer, srcData, signData);
//			System.out.println("国密签名验证是否成功："+flag);
//			return flag;
//		}
		else {
			return false;
		}
	}

	public static String signByMD5(String sourceData, String key)
			throws Exception {
		String data = sourceData + key;
		MessageDigest md5 = MessageDigest.getInstance("MD5");
		byte[] sign = md5.digest(data.getBytes(CHAR_SET));

		return Bytes2HexString(sign).toUpperCase();
	}

	/**
	 * 将byte数组转成十六进制的字符串
	 * 
	 * @param b
	 *            byte[]
	 * @return String
	 */
	public static String Bytes2HexString(byte[] b) {
		StringBuffer ret = new StringBuffer(b.length);
		String hex = "";
		for (int i = 0; i < b.length; i++) {
			hex = Integer.toHexString(b[i] & 0xFF);

			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			ret.append(hex.toUpperCase());
		}
		return ret.toString();
	}

}